﻿using Org.BouncyCastle.Tsp;
using Org.BouncyCastle.X509;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Una.FirmaDigital.EN
{
    public class PdfPKCS7
    {

        public static iTextSharp.text.pdf.security.CertificateInfo.X509Name GetSubjectFields(X509Certificate cert)
        {
            return new iTextSharp.text.pdf.security.CertificateInfo.X509Name((Org.BouncyCastle.Asn1.Asn1Sequence)GetSubject(cert.GetTbsCertificate()));
        }
        public static String VerifyCertificate(X509Certificate cert, X509Crl[] crls, DateTime calendar)
        {
            try
            {
                if (!cert.IsValid(calendar))
                    return "The certificate has expired or is not yet valid";
            }
            catch (Exception e)
            {
                return e.ToString();
            }
            return null;
        }
        /**
            * Get the "subject" from the TBSCertificate bytes that are passed in
            * @param enc A TBSCertificate in a byte array
            * @return a DERObject
         */
        private static Org.BouncyCastle.Asn1.Asn1Object GetSubject(byte[] enc)
        {
            Org.BouncyCastle.Asn1.Asn1InputStream inp = new Org.BouncyCastle.Asn1.Asn1InputStream(new MemoryStream(enc));
            Org.BouncyCastle.Asn1.Asn1Sequence seq = (Org.BouncyCastle.Asn1.Asn1Sequence)inp.ReadObject();
            return (Org.BouncyCastle.Asn1.Asn1Object)seq[seq[0] is Org.BouncyCastle.Asn1.DerTaggedObject ? 5 : 4];
        }


        /**
        * Verifies a timestamp against a KeyStore.
        * @param ts the timestamp
        * @param keystore the <CODE>KeyStore</CODE>
        * @param provider the provider or <CODE>null</CODE> to use the BouncyCastle provider
        * @return <CODE>true</CODE> is a certificate was found
        * @since    2.1.6
        */
        public static bool VerifyTimestampCertificates(TimeStampToken ts, List<X509Certificate> keystore)
        {
            try
            {
                foreach (X509Certificate certStoreX509 in keystore)
                {
                    try
                    {
                        ts.Validate(certStoreX509);
                        return true;
                    }
                    catch
                    {
                    }
                }
            }
            catch
            {
            }
            return false;
        }
        /**
        * Verifies a certificate chain against a KeyStore.
        * @param certs the certificate chain
        * @param keystore the <CODE>KeyStore</CODE>
        * @param crls the certificate revocation list or <CODE>null</CODE>
        * @param calendar the date or <CODE>null</CODE> for the current date
        * @return <CODE>null</CODE> if the certificate chain could be validade or a
        * <CODE>Object[]{cert,error}</CODE> where <CODE>cert</CODE> is the
        * failed certificate and <CODE>error</CODE> is the error message
        */
        public static Object[] VerifyCertificates(X509Certificate[] certs, List<X509Certificate> keystore, X509Crl[] crls, DateTime calendar)
        {
            for (int k = 0; k < certs.Length; ++k)
            {
                X509Certificate cert = certs[k];
                String err = VerifyCertificate(cert, crls, calendar);
                if (err != null)
                    return new Object[] { cert, err };
                foreach (X509Certificate certStoreX509 in keystore)
                {
                    try
                    {
                        if (VerifyCertificate(certStoreX509, crls, calendar) != null)
                            continue;
                        try
                        {
                            cert.Verify(certStoreX509.GetPublicKey());
                            return null;
                        }
                        catch
                        {
                            continue;
                        }
                    }
                    catch
                    {
                    }
                }
                int j;
                for (j = 0; j < certs.Length; ++j)
                {
                    if (j == k)
                        continue;
                    X509Certificate certNext = certs[j];
                    try
                    {
                        cert.Verify(certNext.GetPublicKey());
                        break;
                    }
                    catch
                    {
                    }
                }
                if (j == certs.Length)
                    return new Object[] { cert, "Cannot be verified against the KeyStore or the certificate chain" };
            }
            return new Object[] { null, "Invalid state. Possible circular certificate chain" };
        }

    }
}
